﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "CellStableHeaders.h"
#include "CellDate.h"
#include "CellUtil.h"
#include "CellString.h"
#include "CellStringVector.h"
#include "CellStringConverter.h"

namespace cell
{

//-----------------------------------------------------------------------
TimeDuration::TimeDuration(void)
	: mNumOfDuration(0)
	, mUnit(TimeDuration::MILLISECOND)
{
}
//-----------------------------------------------------------------------
TimeDuration::TimeDuration(const uint64 numOfDuration, const int unit)
	: mNumOfDuration(numOfDuration)
	, mUnit(unit)
{
}
//-----------------------------------------------------------------------
TimeDuration::~TimeDuration(void)
{
}
//-----------------------------------------------------------------------
TimeDuration& TimeDuration::operator=(const TimeDuration& duration)
{
	mNumOfDuration = duration.mNumOfDuration;
	mUnit = duration.mUnit;
	return *this;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::years(int numOfYeas)
{
	TimeDuration duration(numOfYeas, TimeDuration::YEAR);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::months(int numOfMonths)
{
	TimeDuration duration(numOfMonths, TimeDuration::MONTH);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::weeks(int numOfWeeks)
{
	TimeDuration duration(numOfWeeks, TimeDuration::WEEK);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::days(int numOfDays)
{
	uint64 t = (uint64)numOfDays * 24 * 60 * 60;
	TimeDuration duration(t, TimeDuration::SECOND);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::hours(long numOfHours)
{
	TimeDuration duration(numOfHours, TimeDuration::HOUR);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::minutes(long numOfMinutes)
{
	TimeDuration duration(numOfMinutes, TimeDuration::MINUTE);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::seconds(long numOfSeconds)
{
	TimeDuration duration(numOfSeconds, TimeDuration::SECOND);
	return duration;
}
//-----------------------------------------------------------------------
TimeDuration TimeDuration::milliseconds(long numOfMilliseconds)
{
	TimeDuration duration(numOfMilliseconds, TimeDuration::MILLISECOND);
	return duration;
}



//-----------------------------------------------------------------------
Date::Date(void)
{
	mTime = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration diff = mTime - time_t_epoch;
	mTimestamp = diff.total_milliseconds();
}
//-----------------------------------------------------------------------
Date::Date(uint64 absoluteTime)
	: mTimestamp(absoluteTime)
{
	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration time = boost::posix_time::milliseconds(absoluteTime);
	mTime = time_t_epoch + time;
}
//-----------------------------------------------------------------------
Date::Date(uint16 year, uint16 month, uint16 date)
{
	mTime = boost::posix_time::ptime(boost::gregorian::date(year, month, date));

	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration timestamp = mTime - time_t_epoch;
	mTimestamp = timestamp.total_milliseconds();
}
//-----------------------------------------------------------------------
Date::Date(uint16 year, uint16 month, uint16 date, uint16 hours, uint16 minutes, uint16 seconds, uint16 milliseconds)
{
	mTime = boost::posix_time::ptime(boost::gregorian::date(year, month, date),
		boost::posix_time::time_duration(hours, minutes, seconds, milliseconds * 1000));

	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration timestamp = mTime - time_t_epoch;
	mTimestamp = timestamp.total_milliseconds();
}
//-----------------------------------------------------------------------
Date::~Date(void)
{
}
//-----------------------------------------------------------------------
inline uint64 Date::getTime(void)
{
	return mTimestamp;
}
//-----------------------------------------------------------------------
inline uint64 Date::getTime(void) const
{
	return mTimestamp;
}
//-----------------------------------------------------------------------
uint16 Date::getYear(void)
{
	return mTime.date().year();
}
//-----------------------------------------------------------------------
uint16 Date::getYear(void) const
{
	return mTime.date().year();
}
//-----------------------------------------------------------------------
uint16 Date::getMonth(void)
{
	return mTime.date().month();
}
//-----------------------------------------------------------------------
uint16 Date::getMonth(void) const
{
	return mTime.date().month();
}
//-----------------------------------------------------------------------
uint16 Date::getDate(void)
{
	return mTime.date().day();
}
//-----------------------------------------------------------------------
uint16 Date::getDate(void) const
{
	return mTime.date().day();
}
//-----------------------------------------------------------------------
uint16 Date::getDay(void)
{
	return mTime.date().day_of_week();
}
//-----------------------------------------------------------------------
uint16 Date::getDay(void) const
{
	return mTime.date().day_of_week();
}
//-----------------------------------------------------------------------
uint16 Date::getHours(void)
{
	return mTime.time_of_day().hours();
}
//-----------------------------------------------------------------------
uint16 Date::getHours(void) const
{
	return mTime.time_of_day().hours();
}
//-----------------------------------------------------------------------
uint16 Date::getMinutes(void)
{
	return mTime.time_of_day().minutes();
}
//-----------------------------------------------------------------------
uint16 Date::getMinutes(void) const
{
	return mTime.time_of_day().minutes();
}
//-----------------------------------------------------------------------
uint16 Date::getSeconds(void)
{
	return mTime.time_of_day().seconds();
}
//-----------------------------------------------------------------------
uint16 Date::getSeconds(void) const
{
	return mTime.time_of_day().seconds();
}
//-----------------------------------------------------------------------
uint16 Date::getMilliseconds(void)
{
	return mTime.time_of_day().fractional_seconds() / 1000;
}
//-----------------------------------------------------------------------
uint16 Date::getMilliseconds(void) const
{
	return mTime.time_of_day().fractional_seconds() / 1000;
}
//-----------------------------------------------------------------------
ulong Date::getMicroseconds(void)
{
	return mTime.time_of_day().fractional_seconds();
}
//-----------------------------------------------------------------------
ulong Date::getMicroseconds(void) const
{
	return mTime.time_of_day().fractional_seconds();
}
//-----------------------------------------------------------------------
void Date::setTime(uint64 absoluteTime)
{
	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration time = boost::posix_time::milliseconds(absoluteTime);
	mTime = time_t_epoch + time;
	mTimestamp = absoluteTime;
}
//-----------------------------------------------------------------------
Date& Date::operator=(const Date& date)
{
	mTimestamp = date.mTimestamp;
	mTime = date.mTime;
	return *this;
}
//-----------------------------------------------------------------------
bool Date::operator<(const Date& date) const
{
	return (mTime < date.mTime);
}
//-----------------------------------------------------------------------
bool Date::operator>(const Date& date) const
{
	return (mTime > date.mTime);
}
//-----------------------------------------------------------------------
bool Date::operator==(const Date& date) const
{
	return (mTime == date.mTime);
}
//-----------------------------------------------------------------------
bool Date::operator!=(const Date& date) const
{
	return (mTime != date.mTime);
}
//-----------------------------------------------------------------------
bool Date::operator<=(const Date& date) const
{
	return (mTime <= date.mTime);
}
//-----------------------------------------------------------------------
bool Date::operator>=(const Date& date) const
{
	return (mTime >= date.mTime);
}
//-----------------------------------------------------------------------
Date Date::operator+(const TimeDuration& duration) const
{
	Date ret;

	switch (duration.mUnit)
	{
	case TimeDuration::YEAR:
	{
		boost::gregorian::years years(duration.mNumOfDuration);
		ret.mTime = mTime + years;
		break;
	}
	case TimeDuration::MONTH:
	{
		boost::gregorian::months months(duration.mNumOfDuration);
		ret.mTime = mTime + months;
		break;
	}
	case TimeDuration::WEEK:
	{
		boost::gregorian::weeks weeks(duration.mNumOfDuration);
		ret.mTime = mTime + weeks;
		break;
	}
	case TimeDuration::HOUR:
	{
		boost::posix_time::hours hours(duration.mNumOfDuration);
		ret.mTime = mTime + hours;
		break;
	}
	case TimeDuration::MINUTE:
	{
		boost::posix_time::minutes minutes(duration.mNumOfDuration);
		ret.mTime = mTime + minutes;
		break;
	}
	case TimeDuration::SECOND:
	{
		boost::posix_time::seconds seconds(duration.mNumOfDuration);
		ret.mTime = mTime + seconds;
		break;
	}
	default:
		return Date::operator+(duration.mNumOfDuration);
	}

	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	// 同步时间戳
	boost::posix_time::time_duration timestamp = ret.mTime - time_t_epoch;
	ret.mTimestamp = timestamp.total_milliseconds();
	return ret;
}
//-----------------------------------------------------------------------
Date Date::operator-(const TimeDuration& duration) const
{
	Date ret;

	switch (duration.mUnit)
	{
	case TimeDuration::YEAR:
	{
		boost::gregorian::years years(duration.mNumOfDuration);
		ret.mTime = mTime - years;
		break;
	}
	case TimeDuration::MONTH:
	{
		boost::gregorian::months months(duration.mNumOfDuration);
		ret.mTime = mTime - months;
		break;
	}
	case TimeDuration::WEEK:
	{
		boost::gregorian::weeks weeks(duration.mNumOfDuration);
		ret.mTime = mTime - weeks;
		break;
	}
	case TimeDuration::HOUR:
	{
		boost::posix_time::hours hours(duration.mNumOfDuration);
		ret.mTime = mTime - hours;
		break;
	}
	case TimeDuration::MINUTE:
	{
		boost::posix_time::minutes minutes(duration.mNumOfDuration);
		ret.mTime = mTime - minutes;
		break;
	}
	case TimeDuration::SECOND:
	{
		boost::posix_time::seconds seconds(duration.mNumOfDuration);
		ret.mTime = mTime - seconds;
		break;
	}
	default:
		return Date::operator-(duration.mNumOfDuration);
	}

	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	// 同步时间戳
	boost::posix_time::time_duration timestamp = ret.mTime - time_t_epoch;
	ret.mTimestamp = timestamp.total_milliseconds();
	return ret;
}
//-----------------------------------------------------------------------
Date Date::operator+(const uint64 timeDurationInMilliseconds) const
{
	boost::posix_time::time_duration td = boost::posix_time::milliseconds(timeDurationInMilliseconds);
	Date ret;
	ret.mTime = mTime + td;
	ret.mTimestamp = mTimestamp + timeDurationInMilliseconds;
	return ret;
}
//-----------------------------------------------------------------------
Date Date::operator-(const uint64 timeDurationInMilliseconds) const
{
	boost::posix_time::time_duration td = boost::posix_time::milliseconds(timeDurationInMilliseconds);
	Date ret;
	ret.mTime = mTime - td;
	ret.mTimestamp = mTimestamp - timeDurationInMilliseconds;
	return ret;
}
//-----------------------------------------------------------------------
Date& Date::operator+=(const TimeDuration& duration)
{
	switch (duration.mUnit)
	{
	case TimeDuration::YEAR:
	{
		boost::gregorian::years years(duration.mNumOfDuration);
		mTime += years;
		break;
	}
	case TimeDuration::MONTH:
	{
		boost::gregorian::months months(duration.mNumOfDuration);
		mTime += months;
		break;
	}
	case TimeDuration::WEEK:
	{
		boost::gregorian::weeks weeks(duration.mNumOfDuration);
		mTime += weeks;
		break;
	}
	case TimeDuration::HOUR:
	{
		boost::posix_time::hours hours(duration.mNumOfDuration);
		mTime += hours;
		break;
	}
	case TimeDuration::MINUTE:
	{
		boost::posix_time::minutes minutes(duration.mNumOfDuration);
		mTime += minutes;
		break;
	}
	case TimeDuration::SECOND:
	{
		boost::posix_time::seconds seconds(duration.mNumOfDuration);
		mTime += seconds;
		break;
	}
	default:
		return Date::operator+=(duration.mNumOfDuration);
	}

	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	// 同步时间戳
	boost::posix_time::time_duration timestamp = mTime - time_t_epoch;
	mTimestamp = timestamp.total_milliseconds();
	return *this;
}
//-----------------------------------------------------------------------
Date& Date::operator-=(const TimeDuration& duration)
{
	switch (duration.mUnit)
	{
	case TimeDuration::YEAR:
	{
		boost::gregorian::years years(duration.mNumOfDuration);
		mTime -= years;
		break;
	}
	case TimeDuration::MONTH:
	{
		boost::gregorian::months months(duration.mNumOfDuration);
		mTime -= months;
		break;
	}
	case TimeDuration::WEEK:
	{
		boost::gregorian::weeks weeks(duration.mNumOfDuration);
		mTime -= weeks;
		break;
	}
	case TimeDuration::HOUR:
	{
		boost::posix_time::hours hours(duration.mNumOfDuration);
		mTime -= hours;
		break;
	}
	case TimeDuration::MINUTE:
	{
		boost::posix_time::minutes minutes(duration.mNumOfDuration);
		mTime -= minutes;
		break;
	}
	case TimeDuration::SECOND:
	{
		boost::posix_time::seconds seconds(duration.mNumOfDuration);
		mTime -= seconds;
		break;
	}
	default:
		return Date::operator-=(duration.mNumOfDuration);
	}

	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	// 同步时间戳
	boost::posix_time::time_duration timestamp = mTime - time_t_epoch;
	mTimestamp = timestamp.total_milliseconds();
	return *this;
}
//-----------------------------------------------------------------------
Date& Date::operator+=(const uint64 timeDurationInMilliseconds)
{
	boost::posix_time::time_duration td = boost::posix_time::milliseconds(timeDurationInMilliseconds);
	mTime += td;
	mTimestamp += timeDurationInMilliseconds;
	return *this;
}
//-----------------------------------------------------------------------
Date& Date::operator-=(const uint64 timeDurationInMilliseconds)
{
	boost::posix_time::time_duration td = boost::posix_time::milliseconds(timeDurationInMilliseconds);
	mTime -= td;
	mTimestamp -= timeDurationInMilliseconds;
	return *this;
}
//---------------------------------------------------------------------------
const boost::posix_time::time_duration Date::TZ_EA8 = boost::posix_time::time_duration(8, 0, 0);
//---------------------------------------------------------------------------
String Date::convertDateToString(const Date& date, bool msec)
{
	char buf[32] = {0x0};
	if (msec)
	{
		sprintf(buf, "%d-%02d-%02d %02d:%02d:%02d.%03d", date.getYear(), date.getMonth(), date.getDate(),
			date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
	}
	else
	{
		sprintf(buf, "%d-%02d-%02d %02d:%02d:%02d", date.getYear(), date.getMonth(), date.getDate(),
			date.getHours(), date.getMinutes(), date.getSeconds());
	}
	String ret(buf);
	return ret;
}
//---------------------------------------------------------------------------
Date Date::convertStringToDate(const String& date)
{
	Date d;
	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	d.mTime = time_t_epoch;
	d.mTimestamp = 0;

	StringVector l1 = StringUtil::split(date, " ");
	if (l1.size() != 2)
	{
		return d;
	}

	String strYmd = l1[0];
	String strTime = l1[1];

	// 解析年月日
	StringVector ymd = StringUtil::split(strYmd, "-");
	if (ymd.size() != 3)
	{
		return d;
	}

	String strHms;
	StringVector hmsm = StringUtil::split(strTime, ".");
	if (hmsm.size() == 2 || hmsm.size() == 1)
	{
		strHms = hmsm[0];
	}
	else
	{
		return d;
	}

	StringVector hms = StringUtil::split(strHms, ":");
	if (hms.size() != 3)
	{
		return d;
	}

	int nYear = StringConverter::parseInt(ymd[0]);
	int nMonth = StringConverter::parseInt(ymd[1]);
	int nDate = StringConverter::parseInt(ymd[2]);
	int nHours = StringConverter::parseInt(hms[0]);
	int nMinutes = StringConverter::parseInt(hms[1]);
	int nSeconds = StringConverter::parseInt(hms[2]);

	Date resultDate(nYear, nMonth, nDate, nHours, nMinutes, nSeconds);
	return resultDate;
}
//---------------------------------------------------------------------------
Date Date::convertTimeToDate(std::time_t& time)
{
	boost::posix_time::ptime pt = boost::posix_time::from_time_t(time);
	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration timestamp = pt - time_t_epoch;

	uint64 ts = timestamp.total_milliseconds();

	Date d;
	d.mTime = pt;
	d.mTimestamp = ts;
	return d;
}
//---------------------------------------------------------------------------
Date Date::convertTimeToDate(std::tm& time)
{
	boost::posix_time::ptime pt = boost::posix_time::ptime_from_tm(time);
	boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1),
		boost::posix_time::time_duration(0, 0, 0, 0));
	boost::posix_time::time_duration timestamp = pt - time_t_epoch;

	uint64 ts = timestamp.total_milliseconds();

	Date d;
	d.mTime = pt;
	d.mTimestamp = ts;
	return d;
}

} // end namespace cell
